package com.fhnew.app.model.internet;


import android.os.Handler;
import android.os.Message;


import com.fhnew.app.util.HLog;
import com.google.gson.Gson;

import java.io.IOException;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 *  封装网络请求
 *
 *      请求入口 {@link HttpRequest#startRequest}
 *
 *      参数封装工具类  {@link HttpRequest.Parameter}
 *
 *      线程调度工具类 {@link HttpRequest.RequestRunnable}
 *
 */
public abstract class HttpRequest<T>  {

    private static final int CONNECT_TIME_OUT = 30;
    private static final int READ_TIME_OUT = 30;
    private static final int WRITE_TIME_OUT = 30;

//    private boolean isGet  = true;

    private static OkHttpClient client;
    protected static Gson gson;

    private RequestRunnable requestRunnable;

    /**
     * 开始网络请求
     */
    public void startRequest(Parameter parameter){
        if (gson == null)
            gson = new Gson();
        requestOption(parameter);
        onStartedRequest(this);
    }

    /**
     * 停止网络请求
     */
    public void stopRequest(){
        if(requestRunnable!= null)
            requestRunnable.disable();
        error("主动停止网络请求");
    }

    public void onStartedRequest (HttpRequest httpRequest){

    }

    /**
     * 具体的网络请求
     */
    private void requestOption(Parameter parameter){

        //每次请求都是一个新线程，各线程之间数据不互相操作，线程安全
        requestRunnable =   new RequestRunnable(parameter);

        requestRunnable.setActionLisstener(new RequestRunnable.ActionLisstener() {
            @Override
            public Response requestHttpI (Parameter parameter) {
                Response response = null;
                try{
                    response = requestHttp(parameter);
                }catch (Exception e){
                    HLog.E("网络请求异常"+e.toString());
                }
                return response;
            }

            @Override
            public Object decodeResultI (Response response) throws Exception {
                if(response == null)return null;
                String body = response.body().string();
                Object t = decodeResult(body);
                return t;
            }

            @Override
            public void requestEnd (Object o) {
                if(o == null){
                    error("请求失败");
                }else{
                    result((T) o);
                }
            }
        }).execute();

        // ===============RXJava线程调度与reactivex 重复 暂时不用====================
//        Observable.just(parameter)
//                .subscribeOn(Schedulers.io())
//                .parameter(new Func1<Parameter,T>(){
//                    @Override
//                    public T call(Parameter parameter) {
//                        Response response = requestHttpI(parameter);
//                        if (gson == null)
//                            gson = new Gson();
//                        T t = null;
//                        try {
//                            t = decodeResultI(response.body().string());
//                        } catch (Exception e) {
//                            return null;
//                        }
//                        return t;
//                    }
//                })
//                .observeOn(AndroidSchedulers.mainThread())
//                .subscribe(new Action1<T>() {
//                    @Override
//                    public void call(T httpResult) {
//                        if(httpResult == null){
//                            error("解析错误");
//                        }else{
//                            result(httpResult);
//                        }
//                    }
//                }, new Action1<Throwable>() {

//                    @Override
//                    public void call(Throwable throwable) {
//                        error(throwable.getMessage());
//                    }
//                });
    }

    public Response requestHttp(Parameter parameter){

        if(client == null)
            client  = new OkHttpClient.Builder()
                    .connectTimeout(CONNECT_TIME_OUT, TimeUnit.SECONDS)

                    .readTimeout(READ_TIME_OUT, TimeUnit.SECONDS)
                    .writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS)
                    .build();

        Request.Builder builder = new Request.Builder();
        String url = parameter.getUrl();
        HLog.I("网络请求"+(parameter.isGet()?"Get":"Post")+" "+url);
        builder.url(url);
        builder.addHeader("Content-Type", "application/json; charset=utf-8");
        if(parameter.isGet()){
            builder.get();
        }else{
            builder.post(parameter.getRequestBody());
        }
        Request request = builder.build();

        Call call =  client.newCall(request);
        Response response  = null;
        try {
            response =call.execute();
        } catch (IOException e) {
            HLog.E("网络请求异常"+e.toString());
            return null;
        }
        return response;
    }

    //解码数据
    public abstract T decodeResult(String json) throws Exception;

    //解析成功返回数据
    public abstract void result(T result);

    //出现异常时的处理
    public abstract void error(String msg);


    //========================================================================
    //网络请求参数封装
    //========================================================================
    static class Parameter {
        private HashMap<String, String> parameter;
        private HashMap<String,String> setting;

        private static final String URL = "url";

        private static final String METHOD = "method";
        private static final String GET = "get";
        private static final String POST = "post";

        public Parameter(){
            parameter = new HashMap<>();
            setting = new HashMap<>();
        }

        public Parameter setUrl(String url){
            setting.put(URL,url);
            return this;
        }

        public Parameter methodGet(){
            setting.put(METHOD,GET);
            return this;
        }

        public Parameter methodPost(){
            setting.put(METHOD,POST);
            return this;
        }

        public Parameter addValue(String key, String value){
            parameter.put(key,value);
            return this;
        }

        public Parameter addValue(String key, int value){
            parameter.put(key,value+"");
            return this;
        }

        public String getUrl(){
            String url = setting.get(URL);
            if(setting.get(METHOD).equals(GET) && parameter.size()>0){
                Set<String> keySet =  parameter.keySet();
                int index = 0;
                for (String key:keySet) {
                    if(index == 0 && !url.contains("?")){
                        url += "?";
                    }
                    url += "&"+key+"="+ parameter.get(key);
                    index++;
                }
            }
            return url;
        }

        public boolean isGet(){
            if(setting.get(METHOD) == null || setting.get(METHOD).equals(GET)){
                return true;
            }
            return false;
        }


        public RequestBody getRequestBody(){
            if(setting.get(METHOD).equals(POST)){
                Set<String> keySet =  parameter.keySet();
                FormBody.Builder builder =new FormBody.Builder();
                HLog.I(HLog.stackTrace()+"Post 参数");
                for (String key:keySet) {
                    HLog.I(key+"="+parameter.get(key));
                    builder.add(key, parameter.get(key));
                }
                return builder.build();
            }
            return null;
        }
    }

    //========================================================================
    // 网络请求线程封装
    //========================================================================
    public static class RequestRunnable implements Runnable{

        private ActionLisstener actionLisstener;
        private Parameter parameter;

        private static ExecutorService cachedThreadPool  = null;
        private static final int HANDLER_CODE = 0x1001;
        private Object result = null;

        //请求失效标记
        private boolean disable = false;

        private Handler handler = new Handler(){
            @Override
            public void handleMessage (Message msg) {
                super.handleMessage(msg);
                if(msg.what == HANDLER_CODE && !disable){
                    actionLisstener.requestEnd(result);
                }
            }
        };

        public RequestRunnable(Parameter parameter){
            this.parameter = parameter;
        }

        public void disable(){
            disable = true;
        }

        public void execute(){
            if(cachedThreadPool == null){
                cachedThreadPool = Executors.newCachedThreadPool();
            }
            cachedThreadPool.execute(this);
        }

        @Override
        public void run () {
            if(actionLisstener!= null){

                Response response =  actionLisstener.requestHttpI(parameter);

                Object obj = null;
                try {
                    obj =  actionLisstener.decodeResultI(response);
                    result = obj;
                } catch (Exception e) {
                    HLog.E("网络数据解析异常"+e.toString());
                    handler.sendEmptyMessage(HANDLER_CODE);
                }
                handler.sendEmptyMessage(HANDLER_CODE);
            }else{
                handler.sendEmptyMessage(HANDLER_CODE);
            }
        }

        public  RequestRunnable setActionLisstener (ActionLisstener actionLisstener){
            this.actionLisstener = actionLisstener;
            return this;
        }

        public interface ActionLisstener{
            /**
             * 子线程中请求
             * @param parameter
             * @return
             */
            public Response requestHttpI (Parameter parameter);

            /**
             * 子线程中解析
             * @param response
             * @return
             * @throws Exception
             */
            public Object decodeResultI (Response response) throws Exception;

            /**
             * 主线程回调
             * @param t
             */
            public void requestEnd (Object t);
        }

    }


}
